package com.zhz.mall.common.config;

import com.alibaba.fastjson.JSON;
import com.zhz.mall.common.constant.ThreadPoolConstant;
import com.zhz.mall.common.util.threadpool.ErrorLoggingTaskDecorator;
import com.zhz.mall.common.util.threadpool.ThreadPoolUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncExecutionInterceptor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

import static org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME;

/**
 * ThreadPoolConfiguration
 * <p>
 * 线程池配置类
 *
 * @see org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
 * @see org.springframework.boot.autoconfigure.task.TaskExecutionProperties
 * @see org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
 * @see org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
 * @see org.springframework.aop.interceptor.AsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
 * @see org.springframework.aop.interceptor.AsyncExecutionAspectSupport#getDefaultExecutor(org.springframework.beans.factory.BeanFactory)
 * @see ThreadPoolUtils
 * @author zhouhengzhe
 */
@Slf4j
@EnableAsync
@EnableScheduling
@Configuration(proxyBeanMethods = false)
public class BaseThreadPoolConfiguration implements InitializingBean {

    @Autowired
    private TaskExecutionProperties taskExecutionProperties;

    @Autowired
    private TaskSchedulingProperties taskSchedulingProperties;


    @Override
    public void afterPropertiesSet() {
        initTaskExecutionProperties(taskExecutionProperties);
        initTaskSchedulingProperties(taskSchedulingProperties);
    }


    /**
     * 初始化线程池默认参数
     */
    private void initTaskExecutionProperties(TaskExecutionProperties taskExecutionProperties) {
        TaskExecutionProperties.Pool defaultConfig = new TaskExecutionProperties.Pool();
        TaskExecutionProperties.Pool pool = taskExecutionProperties.getPool();
        if (pool.getCoreSize() == defaultConfig.getCoreSize()) {
            pool.setCoreSize(Runtime.getRuntime().availableProcessors() * 2);
        }
        if (pool.getQueueCapacity() == defaultConfig.getQueueCapacity()) {
            pool.setQueueCapacity(500);
        }
        if (pool.getMaxSize() == defaultConfig.getMaxSize()) {
            pool.setMaxSize(200);
        }
        log.info("TaskExecutionProperties: " + JSON.toJSONString(pool));
    }


    /**
     * 初始化调度器默认参数
     */
    private void initTaskSchedulingProperties(TaskSchedulingProperties taskSchedulingProperties) {
        TaskSchedulingProperties.Pool defaultConfig = new TaskSchedulingProperties.Pool();
        TaskSchedulingProperties.Pool pool = taskSchedulingProperties.getPool();
        if (pool.getSize() == defaultConfig.getSize()) {
            pool.setSize(4);
        }
        log.info("TaskSchedulingProperties: " + JSON.toJSONString(pool));
    }


    /**
     * applicationTaskExecutor
     */
    @Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
            AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
    public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
        return builder.build();
    }

    /**
     * MRO库存操作使用
     * @return ThreadPoolTaskExecutor
     */
    @Bean(name = ThreadPoolConstant.MRO_EXECUTOR)
    public ThreadPoolTaskExecutor getMroPoolExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(50);
        executor.setKeepAliveSeconds(15);
        executor.setThreadNamePrefix("Async-fms-mroExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.setQueueCapacity(400);
        executor.initialize();
        return executor;
    }

    /**
     *  收款管理导入 最大支持500条记录同时导入
     *  异步账户资金注册
     *  任务更新成功将回写收款管理记录状态
     *  丢弃的任务 对应的收款管理中记录的状态为未变更
     * @return ThreadPoolTaskExecutor
     */
    @Bean(name = ThreadPoolConstant.C_FUND_EXECUTOR)
    public ThreadPoolTaskExecutor getCFundPoolExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(20);
        executor.setKeepAliveSeconds(10);
        executor.setThreadNamePrefix("Async-fms-cFundExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.setQueueCapacity(400);
        executor.initialize();
        return executor;
    }

    /**
     * 资金账户 流水 核销相关操作
     * TODO 核销事件触发过于频繁
     * @return ThreadPoolTaskExecutor
     */
    @Bean(name = ThreadPoolConstant.C_FUND_ACCOUNT_EXECUTOR)
    public ThreadPoolTaskExecutor getCFundAccountExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(25);
        executor.setMaxPoolSize(25);
        executor.setKeepAliveSeconds(15);
        executor.setThreadNamePrefix("Async-fms-cFundAccountExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.setQueueCapacity(500);
        executor.initialize();
        return executor;
    }

    /**
     * completableFuture专用
     * @return ThreadPoolTaskExecutor
     */
    @Bean(name = ThreadPoolConstant.COMPLETABLE_FUTURE_ASYNC_EXECUTOR)
    public ThreadPoolTaskExecutor getCompletableFutureAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(25);
        executor.setMaxPoolSize(25);
        executor.setKeepAliveSeconds(15);
        executor.setThreadNamePrefix("Async-fms-completableFuture-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setQueueCapacity(500);
        executor.initialize();
        return executor;
    }

    /**
     * 调用三方接口专用
     * @return ThreadPoolTaskExecutor
     */
    @Bean(name = ThreadPoolConstant.CALL_THREE_API_EXECUTOR)
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(25);
        executor.setMaxPoolSize(25);
        executor.setKeepAliveSeconds(15);
        executor.setThreadNamePrefix("Async-fms-cFundAccountExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.setQueueCapacity(500);
        executor.initialize();
        return executor;
    }

    /**
     * 记录线程池的错误日志
     */
    @Bean
    public ErrorLoggingTaskDecorator errorLoggingTaskDecorator() {
        return ErrorLoggingTaskDecorator.INSTANCE;
    }


}
